#include <queue>
#include <unistd.h>
#include <functional>
#include <iostream>
#include <pthread.h>
#include <unistd.h>


const static int defMemNum = 5;

template<class T>
class blockQueue
{
private:
    //判断队列是否为空
    bool Empty()
    {
        return _blockQueue.empty();
    }

    //判断队列是否为满
    bool Full()
    {
        return _blockQueue.size() == _cap;
    }

public:
    blockQueue(size_t cap = defMemNum)
        :_conNum(0)
        ,_proNum(0)
        ,_cap(cap)
    {
        pthread_mutex_init(&_lock, nullptr);
        pthread_cond_init(&_consumerWait, nullptr);
        pthread_cond_init(&_productorWait, nullptr);
    }

    T pop()
    {
        pthread_mutex_lock(&_lock);
        while(Empty())
        {
            _conNum += 1;
            pthread_cond_wait(&_consumerWait, &_lock);
            _conNum -= 1;
        }
        T data = _blockQueue.front();
        _blockQueue.pop();
        if(_proNum > 0)
        {
            pthread_cond_signal(&_productorWait);
        }
        pthread_mutex_unlock(&_lock);
        return data;
    }

    void push(const T &data)
    {
        pthread_mutex_lock(&_lock);
        while (Full())
        {
            _proNum += 1;
            pthread_cond_wait(&_productorWait, &_lock);
            _proNum -= 1;   
        }
        _blockQueue.push(data);
        std::cout << "生产了一个任务: " << std::endl;
        if(_conNum > 0)
        {
            pthread_cond_signal(&_consumerWait);
        }
        pthread_mutex_unlock(&_lock);
        return;
    }
    
    ~blockQueue()
    {
        pthread_mutex_destroy(&_lock);
        pthread_cond_destroy(&_productorWait);
        pthread_cond_destroy(&_consumerWait);
    }
private:
    pthread_mutex_t _lock;          //维护共享资源需要的锁
    pthread_cond_t _consumerWait;   //消费者等待条件
    pthread_cond_t _productorWait;  //生产者等待条件
    std::queue<T> _blockQueue;      //阻塞队列
    size_t _conNum;                 //消费者中的元素数量
    size_t _proNum;                 //生产者的元素数量
    size_t _cap;                    //队列中元素的最大数量
};



// 任务形式
// 我们定义了一个任务类型，返回值void，参数为空
using task_t = std::function<void()>;

void Download()
{
    std::cout << "我是一个下载任务..." << std::endl;
    sleep(3); // 假设处理任务比较耗时
}




void *consumer(void *args)
{
    blockQueue<task_t> *bq = static_cast<blockQueue<task_t> *>(args);

    while (true)
    {
        sleep(1);
        // 1. 消费任务
        task_t t = bq->pop();

        // 2. 处理任务 -- 处理任务的时候，这个任务，已经被拿到线程的上下文中了,不属于队列了
        t();
    }
}

void *productor(void *args)
{
    blockQueue<task_t> *bq = static_cast<blockQueue<task_t> *>(args);
    while (true)
    {
        // 1. 获得任务
        //std::cout << "生产了一个任务: " << x << "+" << y << "=?" << std::endl;
        

        // 2. 生产任务
        bq->push(Download);
    }
}

int main()
{
    // 扩展认识: 阻塞队列: 可以放任务吗？
    // 申请阻塞队列
    blockQueue<task_t> *bq = new blockQueue<task_t>();

    // 构建生产和消费者
    pthread_t c[2], p[3];

    pthread_create(c, nullptr, consumer, bq);
    pthread_create(c+1, nullptr, consumer, bq);
    pthread_create(p, nullptr, productor, bq);
    pthread_create(p+1, nullptr, productor, bq);
    pthread_create(p+2, nullptr, productor, bq);

    pthread_join(c[0], nullptr);
    pthread_join(c[1], nullptr);
    pthread_join(p[0], nullptr);
    pthread_join(p[1], nullptr);
    pthread_join(p[2], nullptr);

    return 0;
}